Node.js HTTP Server

HTTP(Hyper Text Transfer Protocol)即浏览器和服务器之间的传输协议,用于浏览器和服务器之间的通信问题,从握手开始处理 TCP 链接,为实现解析 HTTP 的问题,Node 可以通过其内置的 http 模块来解决此问题。

应用程序并不可以直接和 HTTP 进行一些操作,因此可以通过其 http 模块中所提供的 require(请求) 以及 response(响应) 来将 HTTP 响应返回服务器。

因为 require 封装了 HTTP 请求,因此可以通过使用 require 对象属性方法获取所有的 HTTP 请求信息

同样的因为 response 对象封装了 HTTP 响应,也可以通过此对象方法将 HTTP 响应返回给浏览器

因此 http 模块也可以有两种方式进行使用,服务端创建 HTTP 服务器以此来监听客户端的请求并返回响应,而作为客户端,将发起一个 HTTP 请求(客户端)来获取服务端的响应。

Request at Response

Request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const http = require('http')

// 创建本地服务器来从其接收数据
var server = http.createServer(function (req,res) {
// 获得 HTTP 请求的 method + url
console.log(req.method + ':' + req.url)
req.on('data', function (chunk) {
body.push(chunk)
})

// 向请求发送响应头
res.writeHead(200, {'Content-Type':'text/html'});
// 完成并发送请求
res.end('<h1>Hello,world!</h1>')
})

server.listen(8081)

console.log('Server is running at http://localhost:8081/');

HTTP 请求的本质上就是 Headers 以及 body 两者组成,因此我们首先通过了 http.createServer 来创建一个服务器,然后通过 server.listen() 的方法监听端口,当客户端发出请求时,服务器就会的回调函数就会i被调用,因此输出:

1
2
3
4
5
Server is running at http://localhost:8081/
GET:/
GET:/favicon.ico
GET:/
GET:/favicon.ico

HTTP 请求在发送服务器时,是一个字节一个字节的以数据流方式发送,HTTP 模块创建的 HTTP 服务器接受到完整的请求头后会调用函数,因此除了可以使用 request 对象访问请求头数据以外,还可以将此当作一个只读数据流来访问请求数据提

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const http = require('http')

http.createServer(function (req,res) {
var body = []

console.log(req.method)
console.log(req.headers)

req.on('data', function (chunk) {
body.push(chunk)
})

req.on('end', function () {
body = Buffer.concat(body)
console.log(body.toString())
})
}).listen(8081)

因此输出的是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GET
{ host: 'localhost:8081',
connection: 'keep-alive',
'sec-ch-ua':
'"Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"',
'cache-control': 'no-cache',
'sec-ch-ua-mobile': '?0',
'user-agent':
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36',
'postman-token': '9c86d3ea-3df2-9485-75e6-f8d2af8c0b03',
accept: '*/*',
'sec-fetch-site': 'none',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh-TW;q=0.9,zh;q=0.8,en-US;q=0.7,en;q=0.6' }

Response

客户端发送请求并接受到完整的服务端响应头时,就会调用回调函数,在回调函数中,可以通过 response 对象访问响应头外,还可以将 Response 当作一个只读数据流,其中最为主要的是 http.ServerResponse 所提供的类方法:

Id Name Info
1 response.statusCode HTTP 响应状态码
2 response.headers HTTP 响应头
3 response.statusMessage 当前消息状态
4 response.complete 是否已经接收到了完整的 HTTP 请求头信息
5 response.httpVersion 链接到服务器的HTTP 版本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const http = require('http')

/*
HTTP 状态码: 200
<h1>Hello,world!</h1>
请求头: true
*/
http.get('http://localhost:8081/', function (response) {
var body = []

console.log("HTTP 状态码: ",response.statusCode)

response.on('data', function (chunk) {
body.push(chunk)
})

response.on('end', function () {
body = Buffer.concat(body)
console.log(body.toString())
console.log("是否已经接收完整的 HTTP 信息:" ,response.complete)
})
})

HTTP/2


HTTP/2 是于 19999 年的 HTTP 1.1 的改进版(RFC 2616)后在 2014 年 12 月由 互联网工程任务组(IETF)内的 HTTPBIS(Hypertext Transfer Protocol Bis) 小组进行开发,并由 IETF 递交给 IESG 进行讨论,在 2015 年 5 月 正式批准(RFC 7540)

于 HTTP 1.1 相比支持了多路复用(Multiplexing)、首部压缩(Headers)、服务推送(Server Push) 等特点,有效减少了大量的开销。

服务器推送即允许服务器在客户端缓存中填充数据,通过服务器推送的机制来提前进行请求,但需要安装 http 2 模块

由于 http2 是一个内置模块,与 npm 上的 http2 无关

1
2
3
4
5
6
7
8
9
10
node/
├── package.json
├── package-lock.json
├── public
├── src
│ └── server.js
└── ssl
├── localhost-cert.pem
└── localhost-privkey.pem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const http2 = require('http2');
const express = require('express')
const fs = require('fs');

const server = http2.createSecureServer({
key: fs.readFileSync('./ssl/localhost-privkey.pem'),
cert: fs.readFileSync('./ssl/localhost-cert.pem')
});
server.on('error', (err) => console.error(err));

server.on('stream', (stream, headers) => {
// stream is a Duplex
stream.respond({
'content-type': 'text/html; charset=utf-8',
':status': 200
});
stream.write("<h1>Hello,world!</h1>")
stream.end();
});

server.listen(8443);

之后即可通过 https://localhost:8443/ 直接进行访问,当然由于使用了 ssl 的原因 node 关闭了 http 的访问,因此只可以通过 https 进行,如果是自己生成的证书可能会报错,点击继续访问即可。

可直接通过 openssl 生成自己的本地证书

openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj ‘/CN=localhost’
-keyout localhost-privkey.pem -out localhost-cert.pem

本文使用《江雪分析公开知识存储库知识共享许可证》进行发布